package com.piece.admin.controller.system;

import com.piece.admin.model.TbSysDict;
import com.piece.admin.service.TbSysDictService;
import com.piece.admin.support.TranslateEntity;
import com.piece.core.web.authority.token.CompositeAuthorizationGranter;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.annotation.permission.SubmitPermission;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.bootstrap.TreeData;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.support.response.Select;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.message.enums.SmsChannelType;
import com.piece.core.web.controller.FrameWorkController;
import com.piece.file.enums.FileStorageType;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Api(tags = {"字典管理"})
@RestController
@RequestMapping("/api/system/dict")
public class SysDictController extends FrameWorkController {

    @Autowired
    protected TranslateEntity translateEntity;

    @Resource
    private TbSysDictService tbSysDictService;

    @Autowired(required = false)
    private List<CompositeAuthorizationGranter> compositeAuthorizations;

    @PostMapping("/list")
    @AclPermission(code = "system:dict:view")
    @ApiOperation(value = "查询字典列表")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public List list() {
        QueryTable queryTable = initTable();
        DataTable dataTable = tbSysDictService.findPage(queryTable);
        return dataTable.getData();
    }

    @PostMapping("/table")
    @AclPermission(code = "system:dict:view")
    @ApiOperation(value = "查询字典分页数据")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public AjaxResponse table() {
        QueryTable queryTable = initTable();
        DataTable dataTable = tbSysDictService.findPage(queryTable);
        return success(dataTable);
    }

    @GetMapping("/load")
    @AclPermission(code = "system:dict:view")
    @ApiOperation(value = "生成字典表单数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "字典主键"),
            @ApiImplicitParam(name = "pid", value = "字典父ID")
    })
    public AjaxResponse load() {
        long id = Convert.toLong(getRequest().getParameter("id"), 0L);
        Long pid = Convert.toLong(getRequest().getParameter("pid"), null);
        TbSysDict dict = new TbSysDict();
        if (null != pid) {
            TbSysDict pDict = tbSysDictService.findById(pid);
            dict.setParentCode(pid);
            if (null != pDict) {
                dict.setDictGroup(pDict.getDictGroup());
                dict.setDictType(OptionType.OPTION.getCode());
                dict.setIsLeaf(OptionType.LEAF.getCode());
            } else {
                dict.setDictType(OptionType.GROUP.getCode());
                dict.setIsLeaf(OptionType.NOT_LEAF.getCode());
            }
            long dictSort = tbSysDictService.findNextDictSort(dict);
            dict.setDictSort(dictSort);
            dict.setStatus(StatusType.NORMAL.getCode());
        } else if (id != 0) {
            dict = tbSysDictService.findById(id);
        }
        return success(dict);
    }

    @SubmitPermission
    @PostMapping("/save")
    @AclPermission(code = "system:dict:add,system:dict:edit")
    @ApiOperation(value = "保存字典表单数据")
    @ApiImplicitParam(dataTypeClass = TbSysDict.class)
    public AjaxResponse save() {
        TbSysDict dict = new TbSysDict();
        try {
            initDB(dict);
            if (null != dict.getDictCode() && dict.getDictCode() != 0L) {
                tbSysDictService.update(dict);
            } else {
                tbSysDictService.insert(dict);
            }
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/delete")
    @AclPermission(code = "system:dict:delete")
    @ApiOperation(value = "删除字典")
    @ApiImplicitParam(name = "ids", value = "字典ID集合")
    public AjaxResponse delete() {
        String ids = getRequest().getParameter("ids");
        if (StringUtil.isNotEmpty(ids)) {
            tbSysDictService.delete(Convert.toLongArray(ids));
        }
        return success(I18nUtil.message(ExceptionConstants.DELETE_SUCCESS), null);
    }

    /**
     * 加载所有字典列表树
     */
    @PostMapping("/treeData")
    @ApiOperation(value = "加载所有字典列表树")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "selected", value = "已选ID集合"),
            @ApiImplicitParam(name = "dictGroup", value = "字典所属组"),
            @ApiImplicitParam(name = "from", value = "请求来源")
    })
    public List<TreeData> treeData() {
        String selected = getRequest().getParameter("selected");
        String dictGroup = getRequest().getParameter("dictGroup");
        // 请求来源
        String from = getRequest().getParameter("from");
        List<TreeData> result;
        List<TbSysDict> list;
        boolean group = false;
        if (StringUtil.isNotEmpty(dictGroup)) {
            group = true;
            if ("group".equals(dictGroup)) {
                list = tbSysDictService.findDicGroup();
            } else {
                list = tbSysDictService.findByGroupValue(dictGroup);
            }
        } else {
            list = tbSysDictService.findAll();
        }
        if (StringUtil.isNotEmpty(selected)) {
            result = tbSysDictService.findTreeData(list, true, Convert.toStrList(selected), group);
        } else {
            result = tbSysDictService.findTreeData(list, group);
        }

        if ("vue".equals(from)) {
            TreeData root = TreeData.builder().id("root").name("全部").build();
            if (result.size() == 1) {
                root.setId(result.get(0).getId());
            } else {
                root.setId(result.get(0).getPId());
            }
            result = findChildTreeData(result, Convert.toStr(root.getId(), "0"));
            root.setChildren(result);
            List<TreeData> convertResult = new ArrayList<>();
            convertResult.add(root);
            return convertResult;
        }
        return result;
    }

    @PostMapping("/select")
    @ApiOperation(value = "查询字典下拉列表")
    @ApiImplicitParams({
            @ApiImplicitParam(value = "查询分页条件", dataTypeClass = Select.class, type = "body"),
            @ApiImplicitParam(name = "Q_dictLabel_S_LK", value = "字典中文名称"),
            @ApiImplicitParam(name = "Q_dictLabelEn_S_LK_OR", value = "字典英文名称"),
            @ApiImplicitParam(name = "dictId", value = "字典ID"),
            @ApiImplicitParam(name = "dictGroup", value = "字典所属组"),
            @ApiImplicitParam(name = "selected", value = "已选字典ID")
    })
    public AjaxResponse select() {
        QueryTable queryTable = initSelect("Q_dictLabel_S_LK,Q_dictLabelEn_S_LK_OR");
        String dictId = getRequest().getParameter("dictId");
        String dictGroup = getRequest().getParameter("dictGroup");
        String selected = getRequest().getParameter("selected");

        DataTable dataTable;
        try {
            if (StringUtil.isNotEmpty(dictGroup)) {
                queryTable.getParams().put("Q_dictGroup_S_EQ", dictGroup);
            }
            if (StringUtil.isNotEmpty(dictId)) {
                TbSysDict dict = tbSysDictService.findById(Convert.toLong(dictId));
                if (null != dict) {
                    queryTable.getParams().put("Q_parentCode_L_EQ", dict.getDictCode());
                }
            }
            queryTable.getParams().put("Q_dictType_S_EQ", "01");
            dataTable = tbSysDictService.findPage(queryTable);
        } catch (Exception e) {
            dataTable = new DataTable(queryTable);
            List<TbSysDict> dictList = new ArrayList<>();
            dataTable.setData(dictList);
            dataTable.setRecordsTotal(0);
        }
        if (StringUtil.isNotEmpty(selected)) {
            selected = FrameWorkConstants.SPLIT_PARAM + selected + FrameWorkConstants.SPLIT_PARAM;
        }
        return success(tableToSelect(dataTable, selected));
    }

    private Select tableToSelect(DataTable dataTable, String selected) {
        Select select = Select.builder().build();
        List<TbSysDict> dictList = dataTable.getData();
        List<Select.Entity> entityList = dictList.stream().map(dict -> {
            Select.Entity entity = select.new Entity(Convert.toStr(dict.getDictValue()), Convert.toStr(dict.getDictLabel()));
            return entity;
        }).filter(entity -> {
            if (StringUtil.isNotEmpty(selected)) {
                if (selected.indexOf(FrameWorkConstants.SPLIT_PARAM + entity.getId() + FrameWorkConstants.SPLIT_PARAM) != -1) {
                    return true;
                }
                return false;
            }
            return true;
        }).collect(Collectors.toList());
        select.setTotal(dataTable.getRecordsTotal());
        select.setData(entityList);
        return select;
    }

    /**
     * 加载字典下拉选项
     */
    @GetMapping("/dictGroup")
    @ApiOperation(value = "加载字典下拉菜单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "group", value = "字典所属组名"),
            @ApiImplicitParam(name = "onlyGroup", value = "只显示组数据")
    })
    public List<TbSysDict> getDataGroup() {
        String dictGroup = getRequest().getParameter("group");
        String onlyGroup = getRequest().getParameter("onlyGroup");
        String client = getRequest().getParameter("client");
        if (StringUtil.isNotEmpty(client)) {
            switch (client) {
                case "FileStorageType":
                    return Arrays.stream(FileStorageType.values())
                            .map(storage -> {
                                TbSysDict dict = new TbSysDict();
                                dict.setDictLabel(storage.name());
                                dict.setDictLabelEn(storage.name());
                                dict.setDictValue(storage.getName());
                                return dict;
                            }).collect(Collectors.toList());
                case "SmsChannelType":
                    return Arrays.stream(SmsChannelType.values())
                            .map(channel -> {
                                TbSysDict dict = new TbSysDict();
                                dict.setDictLabel(channel.name());
                                dict.setDictLabelEn(channel.name());
                                dict.setDictValue(channel.getCode());
                                return dict;
                            }).collect(Collectors.toList());
                case "AuthorizedGrantType":
                    List<TbSysDict> list = new ArrayList<>();
                    if (ObjectUtil.isNotEmpty(compositeAuthorizations)) {
                        compositeAuthorizations.stream().forEach(granter -> {
                            TbSysDict dict = new TbSysDict();
                            dict.setDictLabel(granter.grantType);
                            dict.setDictLabelEn(granter.grantType);
                            dict.setDictValue(granter.grantType);
                            list.add(dict);
                        });
                    } else {
                        TbSysDict dict1 = new TbSysDict();
                        dict1.setDictLabel("username_code");
                        dict1.setDictLabelEn("username_code");
                        dict1.setDictValue("username_code");
                        list.add(dict1);
                        TbSysDict dict2 = new TbSysDict();
                        dict2.setDictLabel("mobile_code");
                        dict2.setDictLabelEn("mobile_code");
                        dict2.setDictValue("mobile_code");
                        list.add(dict2);
                        TbSysDict dict3 = new TbSysDict();
                        dict3.setDictLabel("open_id");
                        dict3.setDictLabelEn("open_id");
                        dict3.setDictValue("open_id");
                        list.add(dict3);
                        TbSysDict dict4 = new TbSysDict();
                        dict4.setDictLabel("authorization_code");
                        dict4.setDictLabelEn("authorization_code");
                        dict4.setDictValue("authorization_code");
                        list.add(dict4);
                        TbSysDict dict5 = new TbSysDict();
                        dict5.setDictLabel("refresh_token");
                        dict5.setDictLabelEn("refresh_token");
                        dict5.setDictValue("refresh_token");
                        list.add(dict5);
                        TbSysDict dict6 = new TbSysDict();
                        dict6.setDictLabel("client_credentials");
                        dict6.setDictLabelEn("client_credentials");
                        dict6.setDictValue("client_credentials");
                        list.add(dict6);
                        TbSysDict dict7 = new TbSysDict();
                        dict7.setDictLabel("implicit");
                        dict7.setDictLabelEn("implicit");
                        dict7.setDictValue("implicit");
                        list.add(dict7);
                    }
                    return list;
            }
        } else if (Convert.toBool(onlyGroup, false)) {
            return tbSysDictService.findDicGroup();
        }
        return tbSysDictService.findByDicGroup(dictGroup);
    }
}
